#include "btl_config.h"
#include "fp_timer.h"

// 注意：改定时器会被低功耗使用到，使用时需要关闭低功耗
#define TCFG_USER_TIMER_ENABLE

#ifdef TCFG_USER_TIMER_ENABLE

struct timer_hdl
{
    int index;
    int prd;
};

#define TIMER_TEST 0

static struct timer_hdl hdl;

#define __this (&hdl)

static const u32 timer_div[] = {
    /*0000*/ 1,
    /*0001*/ 4,
    /*0010*/ 16,
    /*0011*/ 64,
    /*0100*/ 2,
    /*0101*/ 8,
    /*0110*/ 32,
    /*0111*/ 128,
    /*1000*/ 256,
    /*1001*/ 4 * 256,
    /*1010*/ 16 * 256,
    /*1011*/ 64 * 256,
    /*1100*/ 2 * 256,
    /*1101*/ 8 * 256,
    /*1110*/ 32 * 256,
    /*1111*/ 128 * 256,
};

#define FP_TIMER 0

#if FP_TIMER == 3
#define APP_TIMER_CLK clk_get("lsb")  // 选osc时钟源
// #define APP_TIMER_CLK 12000000L  // pll12m
// #define MAX_TIME_CNT 0x07ff  // 分频准确范围，更具实际情况调整
// #define MIN_TIME_CNT 0x0030
#define MAX_TIME_CNT  0x7fff
#define MIN_TIME_CNT  0x100
#else /* timer0 or timer1 */
#define APP_TIMER_CLK clk_get("timer")
#define MAX_TIME_CNT  0x7fff
#define MIN_TIME_CNT  0x100
#endif

#if FP_TIMER == 0 /* timer0 */
#define TIMER_CON   JL_TIMER0->CON
#define TIMER_CNT   JL_TIMER0->CNT
#define TIMER_PRD   JL_TIMER0->PRD
#define TIMER_VETOR IRQ_TIME0_IDX
#elif FP_TIMER == 1 /* timer1 */
#define TIMER_CON   JL_TIMER1->CON
#define TIMER_CNT   JL_TIMER1->CNT
#define TIMER_PRD   JL_TIMER1->PRD
#define TIMER_VETOR IRQ_TIME1_IDX
#elif FP_TIMER == 3 /* timer3 */
#define TIMER_CON   JL_TIMER3->CON
#define TIMER_CNT   JL_TIMER3->CNT
#define TIMER_PRD   JL_TIMER3->PRD
#define TIMER_VETOR IRQ_TIME3_IDX
#endif

#define TIMER_UNIT_MS 1 // 1ms起一次中断
#define MAX_TIMER_PERIOD_MS (1000 / TIMER_UNIT_MS)

/*-----------------------------------------------------------*/
static volatile u32 delay_cnt = 0;

void user_delay_nus(u32 usec)
{
    JL_TIMER2->CON = BIT(14);
    JL_TIMER2->CNT = 0;
    JL_TIMER2->PRD = clk_get("lsb") / 1000000L * usec; // 1us
    JL_TIMER2->CON = BIT(0);                           // sys clk
    // JL_TIMER1->CON = BIT(0) | BIT(3);
    while ((JL_TIMER2->CON & BIT(15)) == 0)
        ;
    JL_TIMER2->CON = BIT(14);
}

void user_delay_nms(int cnt)
{
    delay_cnt = cnt;

    while (delay_cnt)
        ;
}

#if TIMER_TEST
#define test_timer_init()                      \
    do {                                    \
        gpio_set_die(IO_PORT_DM, 1);       \
        gpio_set_direction(IO_PORT_DM, 0); \
        gpio_write(IO_PORT_DM, 1);         \
    } while (0)

#define test_timer_h() gpio_write(IO_PORT_DM, 1)
#define test_timer_l() gpio_write(IO_PORT_DM, 0)
#endif

static u8 io_status = 0;
void __attribute__((weak)) timer_1ms_handler()
{
    /* putchar('a'); */
    // if (io_status) {
    //     gpio_direction_output(IO_PORTA_06, 1);
    //     io_status = 0;
    // } else {
    //     gpio_direction_output(IO_PORTA_06, 0);
    //     io_status = 1;
    // }
}

___interrupt static void timer0_isr()
{
    // bf_print_d("xxxxx");
#if 1
    static u32 cnt1 = 0;

    //   irq_handler_enter(TIME1_INT);

    TIMER_CON |= BIT(14);
#if TIMER_TEST
    test_timer_l();
    test_timer_h();
#endif
    ++cnt1;

#ifdef __BFXX_FINGERPRINT__
    btl_timer_ms_handle(1);
    fp_timer_handle(1);
#endif
    timer_1ms_handler();

    if (delay_cnt)
    {
        delay_cnt--;
    }

    if (!(cnt1 % 5))
    { // 5ms
        /* r_printf("a"); */
    }

    if (cnt1 == 500)
    { // 500ms
        /* putchar('!'); */
        cnt1 = 0;
    }
    //    irq_handler_exit(TIME1_INT);
#endif
}

___interrupt
void timer3_isr(void)
{
    bf_print_d("xxxxx");
    TIMER_CON |= BIT(14);
    // TIMER_CNT = 0;

    #ifdef __BFXX_FINGERPRINT__
    btl_timer_ms_handle(1);
    fp_timer_handle(1);
#endif
    timer_1ms_handler();

}

int timerx_init()
{
    u32 prd_cnt;
    u8 index;

    printf("%s :%d", __func__, __LINE__);

    for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++)
    {
        prd_cnt = TIMER_UNIT_MS * (APP_TIMER_CLK / 1000) / timer_div[index];
        if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT)
        {
            break;
        }
    }
    __this->index = index;
    __this->prd = prd_cnt;

    TIMER_CNT = 0;
    TIMER_PRD = prd_cnt; // 1ms
    request_irq(TIMER_VETOR, 1, timer0_isr, 0);
    TIMER_CON = (index << 4) | BIT(0) | BIT(3);

    printf("PRD : 0x%x / %d", TIMER_PRD, clk_get("timer"));

    return 0;
}

void timer3_init(void)
{
    u32 prd_cnt;
    u8 index;

    for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++)
    {
        prd_cnt = TIMER_UNIT_MS * (APP_TIMER_CLK / 1000) / timer_div[index];
        if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT)
        {
            break;
        }
    }
    __this->index = index;
    __this->prd = prd_cnt;

    request_irq(TIMER_VETOR, 3, timer3_isr, 0);
    TIMER_CON = (index << 4) | BIT(0);
}

#endif


static uint32_t g_systic_value = 0;

void timer_handle(void* p)
{
    bf_print_d("timer");
#ifdef __BFXX_FINGERPRINT__
    btl_timer_ms_handle(TIMEROUT);
    fp_timer_handle(TIMEROUT);
#endif
}

//AC632X的范例，其他芯片可能需要小改
/////下面函数调用的使用函数都必须放在ram，中断频率小于1ms的，都建议加AT_VOLATILE_RAM_CODE，将代码指定到ram
___interrupt AT_VOLATILE_RAM_CODE static void timer3_1ms_isr()
{
    JL_TIMER3->CON |= BIT(14);
    static u8 flag = 0;
    if (flag) {
        flag = 0;
        /* gpio_set_output_value(IO_PORTA_04, 0); */
        JL_PORTA->OUT &= ~BIT(8);
    } else {
        flag = 1;
        /* gpio_set_output_value(IO_PORTA_04, 1); */
        JL_PORTA->OUT |= BIT(8);
    }
    // clsSleepCountAdd();//sleep count add
    // g_systic_value++;
    // g_motor_counts++;
    // btl_timer_ms_handle(TIMER_IRQ_TIMES_MS);
#ifdef __BFXX_FINGERPRINT__
    btl_timer_ms_handle(1);
    fp_timer_handle(1);
#endif
    timer_1ms_handler();
}

void timer3_1ms_init(void)
{
    // bf_print_d("%s[%d]", __func__, clk_get("lsb"));
    u32 prd_cnt;
    prd_cnt = clk_get("lsb") / 1000 / 4 / 10 * 10;  // 需要几倍就改最后 *
    // bf_print_d("%s[0x%08x]", __func__, prd_cnt);

    request_irq(IRQ_TIME3_IDX, 3, timer3_1ms_isr, 0);
    JL_TIMER3->CNT = 0;
    JL_TIMER3->PRD = prd_cnt;
    JL_TIMER3->CON = (1 << 4) | (1 << 0);  // lsb clk 4分频
}

void fp_timer_init(void)
{
#if TIMER_TEST
    test_timer_init();
#endif
#if FP_TIMER == 3
    timer3_init();
#else
    // timerx_init();
    timer3_1ms_init();
#endif
}

void delay_ms_rcl(uint32_t count)
{
#define RCL_MS_CNT 27500
    int i, cnt;
    for (i = 0; i < count; i++) {
        cnt = 0;
        while (cnt++ < RCL_MS_CNT) {
            asm("nop");
        }
    }
}

void delay_us_rcl(uint32_t count)
{
#define RCL_US_CNT 26
    int i, cnt;
    for (i = 0; i < count; i++) {
        cnt = 0;
        while (cnt++ < RCL_US_CNT) {
            asm("nop");
        }
    }
}

void fp_timer_delay_us(uint32_t count)
{
    // user_delay_nus(count);
    delay_us_rcl(count);
}

void fp_timer_delay_ms(uint32_t count)
{
    // user_delay_nms(count);
    delay_ms_rcl(count);
}

void delayms(void (*callback)(void), uint32_t timeout)
{
    uint32_t a = fp_timer_get();
    uint32_t b = 0;
    do {
        b = fp_timer_get();
        if (callback)
            callback();
    } while ((b - a) < timeout);
}

void delay_count(int count)
{
    while (count-- > 0)
    {
        ;
    }
}

#define _FP_UINT32_MAX_ 0xFFFFFFFF

void fp_timer_handle(int n)
{
    g_systic_value += n;
}

unsigned int fp_timer_get(void)
{
    return g_systic_value;
}

unsigned int fp_timer_diff_of(unsigned int begin)
{
    unsigned int now = fp_timer_get();
    return (now - begin);
}
